import { plainToInstance } from 'class-transformer';
import {
  IsString,
  IsNotEmpty,
  IsEnum,
  IsNumber,
  Max,
  Min,
  validateSync,
  IsBoolean,
} from 'class-validator';
import { EnvironmentEnum, LogLevelEnum } from '../enums/env.enum';

class EnvironmentVariables {
  @IsNumber()
  @Min(0)
  @Max(65535)
  APP_PORT: number;

  @IsEnum(EnvironmentEnum)
  APP_ENV: EnvironmentEnum;

  @IsString()
  @IsNotEmpty()
  DATABASE_URL: string;

  @IsString()
  @IsNotEmpty()
  DB_USERNAME: string;

  @IsString()
  @IsNotEmpty()
  DB_PASSWORD: string;

  @IsString()
  @IsNotEmpty()
  DB_DATABASE: string;

  @IsNumber()
  @Min(0)
  @Max(65535)
  DB_PORT: number;

  @IsString()
  @IsNotEmpty()
  REDIS_HOST: string;

  @IsString()
  REDIS_PASSWORD: string;

  @IsString()
  @IsNotEmpty()
  REDIS_PORT: string;

  @IsBoolean()
  @IsNotEmpty()
  DB_SYNC: boolean;

  @IsEnum(LogLevelEnum)
  LOG_LEVEL: LogLevelEnum;

  @IsBoolean()
  @IsNotEmpty()
  TIMESTAMP: boolean;

  @IsBoolean()
  @IsNotEmpty()
  LOG_ON: boolean;

  @IsString()
  @IsNotEmpty()
  JWT_PUBLIC_KEY: string;

  @IsString()
  @IsNotEmpty()
  JWT_PRIVATE_KEY: string;

  @IsString()
  @IsNotEmpty()
  JWT_ACCESS_TOKEN_EXPIRES_IN: string;

  @IsString()
  @IsNotEmpty()
  JWT_REFRESH_TOKEN_EXPIRES_IN: string;

  @IsString()
  @IsNotEmpty()
  EMAIL_HOST: string;

  @IsNumber()
  @IsNotEmpty()
  EMAIL_PORT: number;

  @IsString()
  @IsNotEmpty()
  EMAIL_NAME: string;

  @IsString()
  @IsNotEmpty()
  EMAIL_USER: string;

  @IsString()
  @IsNotEmpty()
  EMAIL_PASS: string;

  @IsString()
  @IsNotEmpty()
  UPLOAD_ADDRESS: string;
}

export function validate(config: Record<string, unknown>) {
  const validatedConfig = plainToInstance(EnvironmentVariables, config, {
    enableImplicitConversion: true,
  });
  const errors = validateSync(validatedConfig, {
    skipMissingProperties: false,
  });

  if (errors.length > 0) {
    throw new Error(errors.toString());
  }
  return validatedConfig;
}
